from odoo import fields, models, api
from odoo.exceptions import UserError, ValidationError
from ...functions.common import is_continuous

# 重量区间类型 (提出来是因为有其他地方的selection字段同样使用)
WEIGHT_TYPE = [('lopen_rclose', '左开右闭'), ('lclose_ropen', '左闭右开')]


class RPWeightGradientTemplate(models.Model):
    _name = 'rp.weight.gradient.template'
    _description = '重量梯度模板'
    _sql_constraints = [('unique_name', 'UNIQUE(name)', '名称必须唯一')]

    name = fields.Char(string='模板名称', required=True, copy=False, index=True)

    type = fields.Selection(string='区间类型', selection=WEIGHT_TYPE, default=WEIGHT_TYPE[0][0], required=True)

    inf = fields.Float(string='下确界', compute='_depends_compute_bounds', store=True, digits=(5, 2), default=0)
    sup = fields.Float(string='上确界', compute='_depends_compute_bounds', store=True, digits=(5, 2), default=0)

    weight_gradient_template_ids = fields.One2many(string='关联主表', comodel_name='rp.weight.gradient.template.line', inverse_name='weight_gradient_template_id')

    @api.depends('weight_gradient_template_ids.min_weight', 'weight_gradient_template_ids.max_weight')
    def _depends_compute_bounds(self):
        """ 计算上确界和下确界 """
        for s in self:
            if s.weight_gradient_template_ids:
                intervals = []
                for wgt in s.weight_gradient_template_ids:
                    intervals.append((wgt.min_weight, wgt.max_weight))
                flag, inf, sup = is_continuous(intervals)
                if not flag:
                    raise UserError('所配置的重量梯度非连续')
                s.write({'inf': inf, 'sup': sup})


class RPWeightGradientTemplateLine(models.Model):
    _name = 'rp.weight.gradient.template.line'
    _description = '重量梯度模板明细'
    _order = 'min_weight ASC'

    def _default_get_kg(self):
        kg = self.env['uom.uom'].search([('name', '=', 'kg')])
        return kg.id if kg else False

    display_name = fields.Char(string='展示名称', compute='_depends_fulfill_display_name', store=True)

    weight_gradient_template_id = fields.Many2one(string='关联子表', comodel_name='rp.weight.gradient.template', ondelete='cascade')

    min_weight = fields.Float(string='最小重量', digits=(5, 2), default=0)
    max_weight = fields.Float(string='最大重量', digits=(5, 2), default=0)
    uom_id = fields.Many2one(string='重量单位', comodel_name='uom.uom', default=_default_get_kg)

    carry_value = fields.Float(string='进位值', digits=(3, 2), default=1)

    @api.depends('min_weight', 'max_weight', 'uom_id', 'carry_value')
    def _depends_fulfill_display_name(self):
        for s in self:
            min = str(round(s.min_weight, 2)) if s.min_weight or s.min_weight == 0 else '*'
            max = str(round(s.max_weight, 2)) if s.max_weight else '*'
            uom = str(s.uom_id.name) if s.uom_id else '/'
            carry = str(s.carry_value) if s.carry_value else "*"
            s.write({'display_name': "{} - {} ({}) ->{}".format(min, max, uom, carry)})

    @api.constrains('min_weight', 'max_weight', 'weight_gradient_template_id')
    def _check_weight_range(self):
        for record in self:
            # 检查区间是否有效（最小重量应小于最大重量）
            if record.min_weight >= record.max_weight:
                raise ValidationError('最大重量必须大于最小重量')

            # 检查区间是否重叠(左开右闭)
            overlapping_ranges = self.search([('id', '!=', record.id),
                                              ('weight_gradient_template_id', '=', record.weight_gradient_template_id.id),
                                              ('min_weight', '<', record.max_weight),
                                              ('max_weight', '>', record.min_weight)])
            # '|', '|', '&', ('min_weight', '<', record.max_weight), ('max_weight', '>=', record.max_weight),
            # '&', ('min_weight', '<=', record.min_weight), ('max_weight', '>', record.max_weight),
            #  '&', ('min_weight', '>', record.min_weight), ('max_weight', '<', record.max_weight)])
            if overlapping_ranges:
                raise ValidationError('存在重叠的重量区间')
